package com.airport.schedule;

import com.airport.schedule.model.Flight;
import com.airport.schedule.model.FlightGate;
import com.airport.schedule.util.DateUtil;
import com.airport.schedule.util.ListUtil;
import com.airport.schedule.util.Pair;

import java.util.*;
import java.util.stream.Collectors;

public class ProblemManager {

    private final List<FlightGate> flightGates;
    private final List<Flight> flights;
    private final int totalFlights;
    private int totalPeople;
    private Set<Flight> noRegularGateFlights;

    public ProblemManager(String filename, int limit) {
        ProblemLoader.loads(filename, limit);
        this.flightGates = ProblemLoader.getFlightGates();
        this.totalFlights = ProblemLoader.getFlights().size();
        for(Flight flight : ProblemLoader.getFlights()) {
            totalPeople += flight.getNumPeople();
        }
        this.flights = ProblemLoader.getFlights().stream().filter(f->{
            for(FlightGate gate : flightGates) {
                if(f.isNormalFlight() && gate.acceptFlight(f)) {
                    return true;
                }
            }
            return false;
        }).collect(Collectors.toList());
        this.noRegularGateFlights = new HashSet<>();
        System.out.println("总航班数量="+totalFlights+" 实际参与调度的航班数="+flights.size()
                +" 总共有可用机位数="+flightGates.size());
    }

    public ProblemManager(String filename) {
        this(filename, 10000);
    }

    public List<Flight> getFlights() {
        return flights;
    }

    public List<FlightGate> getFlightGates() {
        return flightGates;
    }

    public int getTotalFlights() {
        return totalFlights;
    }

    public int getTotalPeople() {
        return totalPeople;
    }

    public void addNoRegularGateFlights(Collection<Flight> flights) {
        this.noRegularGateFlights.addAll(flights);
    }

    public Set<Flight> getNoRegularGateFlights() {
        return noRegularGateFlights;
    }

    public Problem genProblem() {
        return new Problem(flights, flightGates);
    }

    public List<Problem> genProblems(boolean useAdHocGate) {
        List<Problem> problems = new ArrayList<>();
        Map<String, Pair<Set<FlightGate>, Set<Flight>>> runwayGroups = new HashMap<>();
        for(FlightGate gate : flightGates) {
            if(!useAdHocGate && gate.isAdHocGate()) continue;
            Pair<Set<FlightGate>, Set<Flight>> p1 =
                    runwayGroups.getOrDefault(gate.getRunwayIn(), new Pair<>());
            if(p1.head == null) {
                p1.head = new HashSet<>();
                p1.tail = new HashSet<>();
            }
            p1.head.add(gate);
            runwayGroups.put(gate.getRunwayIn(), p1);
            Pair<Set<FlightGate>, Set<Flight>> p2 =
                    runwayGroups.getOrDefault(gate.getRunwayOut(), new Pair<>());
            if(p2.head == null) {
                p2.head = new HashSet<>();
                p2.tail = new HashSet<>();
            }
            p2.head.add(gate);
            runwayGroups.put(gate.getRunwayOut(), p2);
        }
        for(Flight flight : flights) {
            boolean assignSuc = false;
            for(Pair<Set<FlightGate>, Set<Flight>> p : runwayGroups.values()) {
                for(FlightGate gate : p.head) {
                    if(gate.acceptFlight(flight)) {
                        p.tail.add(flight);
                        assignSuc = true;
                        break;
                    }
                }
            }
            if(!assignSuc) { // 必须采取临时措施的机位
                noRegularGateFlights.add(flight);
            }
        }
        for(Pair<Set<FlightGate>, Set<Flight>> p : runwayGroups.values()) {
            problems.add(new Problem(p.tail, p.head));
        }

        while (true) {
            List<Problem> subProblems = new ArrayList<>();
            boolean hasMerged = false;
            while(!problems.isEmpty()) {
                Problem problem = problems.remove(0);
                List<Problem> merged = new ArrayList<>();
                for(Problem pro : problems) {
                    if(problem.canMerge(pro)) {
                        problem.merge(pro);
                        merged.add(pro);
                        hasMerged = true;
                    }
                }
                problems.removeAll(merged);
                subProblems.add(problem);
            }
            if(!hasMerged) {
                List<Problem> finalProblems = new ArrayList<>();
                for(Problem problem : subProblems) {
                    if(problem.isValidProblem())
                        finalProblems.add(problem);
                }
                return finalProblems;
            }
            problems = subProblems;
        }
    }

    public List<Problem> splitProblemsByDay() {
        Map<String, List<Flight>> eachDayFlights = new TreeMap<>();
        flights.forEach(f->{
            String date = DateUtil.getPrefix(f.getArrivalTime());
            List<Flight> dayFlights = eachDayFlights.getOrDefault(date, new ArrayList<>());
            dayFlights.add(f);
            eachDayFlights.put(date, dayFlights);
        });
        List<Problem> problems = new ArrayList<>();
        eachDayFlights.forEach(
                (date, dayFlights)->problems.add(new Problem(dayFlights, flightGates, date)));
        List<Problem> mergedProblem = new ArrayList<>();
        for(int i = 0; i < problems.size(); i += 2) {
            problems.get(i).merge(problems.get(i+1));
            mergedProblem.add(problems.get(i));
        }
        if(problems.size() % 2 != 0) {
            mergedProblem.add(problems.get(problems.size()-1));
        }
        return mergedProblem;
    }

    public static void main(String args[]) {
        ProblemManager manager = new ProblemManager("/Users/carlxie/Downloads/airportdata/data.xlsx");
        Collections.sort(manager.flights, (f1,f2)->f1.getNumPeople()-f2.getNumPeople());
        manager.flights.forEach(System.out::println);
    }

}
